package org.saxing.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

/**
 * alibaba box
 *
 * 思路： 优先存放大盒子，大盒子放不下，再试小盒子
 *       一个盒子放入后， 会产生切面，可以将剩余空间继续切分
 *
 * Created by saxing on 2018/6/13.
 */
public class TestBox {

    public static void main(String[] args){
        // 获取盒子
        Box[] boxes = Box.getRandomBox(3);

        // 只有体积最大的那个，才可能装下其他盒子
        Box[] sortedBox = BoxUtil.sortBox(boxes);
        System.out.println(Arrays.asList(sortedBox));

        // 盒子在角落有6种摆法，那产生的情况：每多一个盒子，情况数 * 6
        // 每次摆放产生三个切面
        ExecutorService executor = new ThreadPoolExecutor(6, 60, 3,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(3));

        Future<String> future = executor.submit(new Calculate(0, boxes));
        try {
            System.out.println(future.get());
        } catch (InterruptedException | ExecutionException e) {
            System.out.println("处理过程异常");
        }
    }
}


/**
 * 计算盒子是否放得下
 *
 */
class Calculate implements Callable<String>{

    private int position;
    private Box[] boxes;

    Calculate(int position, Box[] boxes) {
        this.position = position;
    }

    @Override
    public String call() throws Exception {
        // 对不同摆放位置的盒子进行不同计算
        Box[] pBox = BoxUtil.get6PositionBox(boxes[position + 1]);
        for (Box box : pBox){
            if (BoxUtil.fixThreeBorder(boxes[position], boxes[position + 1])){

            }
        }

        // saxing todo
        return "";
    }
}


/**
 * 盒子
 *
 * 抽象出的模型，有长宽高三个属性
 */
class Box{

    /**
     * 长
     */
    private int length;

    /**
     * 宽
     */
    private int width;

    /**
     * 高
     */
    private int height;

    /**
     * 体积
     */
    private int volume;

    /**
     * Box构造函数
     *
     * @param length 长
     * @param width 宽
     * @param height 高
     */
    public Box(int length, int width, int height) {
        this.length = length;
        this.width = width;
        this.height = height;
        volume = this.length * this.width * this.height;
    }

    /**
     * 获取随机大小的例子
     *
     * @param num 盒子个数
     * @return 盒子数组
     */
    public static Box[] getRandomBox(int num){
        Box[] boxes = new Box[num];
        Random random = new Random();
        //生成随机盒子
        for (int i = 0; i < num; i++){
            boxes[i] = new Box(random.nextInt(100), random.nextInt(100), random.nextInt(100));
        }
        return boxes;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getVolume() {
        return volume;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }

    @Override
    public String toString() {
        return "Box{" +
                "length=" + length +
                ", width=" + width +
                ", height=" + height +
                ", volume=" + volume +
                '}';
    }
}

/**
 * 盒子运算工具
 */
class BoxUtil{
    /**
     * 验证三边是否都满足要求, 即是否小盒子能放在大盒子里
     *
     * @return true=是  false=否
     */
    public static boolean fixThreeBorder(Box big, Box small){
        if (big.getHeight() >= small.getHeight()
                && big.getWidth() >= small.getWidth()
                && big.getLength() >= small.getLength()){
            return true;
        }
        return false;
    }

    /**
     * 盒子体积排序
     *
     * @param boxes 盒子
     * @return
     */
    public static Box[] sortBox(Box[] boxes) {
        // 此处可做抽象，兼容更多排序算法
        for (int i = 0; i < boxes.length - 1; i++){
            for (int j = 1; j < boxes.length; j++){
                if (boxes[i].getVolume() < boxes[j].getVolume()){
                    Box temp = boxes[i];
                    boxes[i] = boxes[j];
                    boxes[j] = temp;
                }
            }
        }
        return boxes;
    }

    /**
     * 获取6种摆放形式的盒子
     *
     * @param box
     * @return
     */
    public static Box[] get6PositionBox(Box box){
        Box box1 = new Box(box.getLength(), box.getWidth(), box.getHeight());
        Box box2 = new Box(box.getLength(), box.getHeight(), box.getWidth());
        Box box3 = new Box(box.getWidth(), box.getLength(), box.getHeight());
        Box box4 = new Box(box.getWidth(), box.getHeight(), box.getLength());
        Box box5 = new Box(box.getHeight(), box.getLength(), box.getWidth());
        Box box6 = new Box(box.getHeight(), box.getWidth(), box.getLength());
        return new Box[]{box1, box2, box3, box4, box5, box6};
    }

    /**
     * 每当一个盒子放入大盒子之后，又可以将先例空间切割出多种不同的盒子
     *
     * @param fatherBox 父空间
     * @param sonBox 切出的空间虚拟盒子
     * @return 假想的切出的盒子可能性
     */
    public static Box[] cutBox(Box fatherBox, Box sonBox){
        List<Box> boxes = new ArrayList<>();
        // 以长为主切
        Box box1 = new Box(fatherBox.getLength() - sonBox.getLength(), fatherBox.getWidth(), fatherBox.getHeight());
        Box box2 = new Box(sonBox.getLength(), fatherBox.getWidth(), fatherBox.getHeight() - sonBox.getHeight());
        Box box3 = new Box(sonBox.getLength(), fatherBox.getWidth() - sonBox.getWidth(), sonBox.getHeight());
        Box box4 = new Box(sonBox.getLength(), sonBox.getWidth(), fatherBox.getHeight() - sonBox.getHeight());
        Box box5 = new Box(sonBox.getLength(), fatherBox.getWidth() - sonBox.getWidth(), fatherBox.getHeight());

        //以宽为主切
        Box box6 = new Box(fatherBox.getLength(), fatherBox.getLength() - sonBox.getLength(), fatherBox.getHeight());
        Box box7 = new Box(fatherBox.getLength(), sonBox.getWidth(), fatherBox.getHeight() - sonBox.getHeight());
        Box box8 = new Box(fatherBox.getLength() - sonBox.getLength(), sonBox.getWidth(), sonBox.getHeight());
        Box box9 = new Box(sonBox.getLength(), sonBox.getWidth(), fatherBox.getHeight() - sonBox.getHeight());
        Box box10 = new Box(fatherBox.getLength() - sonBox.getLength(), sonBox.getWidth(), fatherBox.getHeight());

        //以高为主切
        Box box11 = new Box(fatherBox.getLength(), fatherBox.getWidth(), fatherBox.getHeight() - sonBox.getHeight());
        Box box12 = new Box(fatherBox.getLength() - sonBox.getLength(), fatherBox.getWidth(), sonBox.getHeight());
        Box box13 = new Box(sonBox.getLength(), fatherBox.getWidth() - sonBox.getWidth(), sonBox.getHeight());
        Box box14 = new Box(fatherBox.getLength() - sonBox.getLength(), sonBox.getWidth(), sonBox.getHeight());
        Box box15 = new Box(fatherBox.getLength(), fatherBox.getWidth() - sonBox.getWidth(), sonBox.getHeight());

        // 去除长宽高任意为0的空间
        boxes.add(box1);
        boxes.add(box2);
        boxes.add(box3);
        boxes.add(box4);
        boxes.add(box5);
        boxes.add(box6);
        boxes.add(box7);
        boxes.add(box8);
        boxes.add(box9);
        boxes.add(box11);
        boxes.add(box12);
        boxes.add(box13);
        boxes.add(box14);
        boxes.add(box15);
        // 去除长宽高为0的立方体
        return remove0Box(boxes);
    }

    /**
     * 去除长宽高为0的立方体
     *
     * @param boxlist boxlist
     * @return 排除长、宽、高为0的情况
     */
    private static Box[] remove0Box(List<Box> boxlist){
        List<Box> boxes = new ArrayList<>();
        for (Box box : boxlist){
            if (0 != box.getHeight() && 0 != box.getWidth() && 0 != box.getLength()){
                boxes.add(box);
            }
        }
        return boxes.toArray(new Box[boxes.size()]);
    }
}
